from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QPushButton,
                           QFileDialog, QLabel, QRadioButton, QButtonGroup,
                           QMessageBox, QGroupBox, QHBoxLayout,
                           QProgressDialog)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt5.QtGui import QFont
from core.packager import Packager
from core.validator import validate_python_file
from utils.logger import get_logger
from utils.icons import get_app_icon
from config.settings import settings
from pathlib import Path
import shutil
from PIL import Image
import os
import time

logger = get_logger()

class PackageWorker(QThread):
    """打包工作线程，用于后台执行打包任务"""
    progress = pyqtSignal(int)  # 发送打包进度(0-100)
    finished = pyqtSignal(bool, str)  # 发送完成状态和消息
    
    def __init__(self, packager, python_file, is_single_file, show_console=True):
        super().__init__()
        self.packager = packager
        self.python_file = python_file
        self.is_single_file = is_single_file
        self.show_console = show_console
        
    def run(self):
        """执行打包任务的主要逻辑"""
        try:
            # 使用循环模拟更平滑的进度
            for i in range(0, 30, 2):  # 0-30%: 验证文件
                self.progress.emit(i)
                self.msleep(50)  # 添加小延迟使进度更平滑
            
            logger.info('开始验证文件...')
            if not validate_python_file(self.python_file):
                raise Exception("Python文件验证失败")
                
            for i in range(30, 60, 2):  # 30-60%: 准备环境和收集依赖
                self.progress.emit(i)
                self.msleep(50)
            
            logger.info('准备打包环境...')
            logger.info('正在收集依赖...')
            
            for i in range(60, 90, 2):  # 60-90%: 执行打包
                self.progress.emit(i)
                self.msleep(50)
            
            logger.info('正在执行打包...')
            self.packager.package(self.python_file, self.is_single_file, self.show_console)
            
            for i in range(90, 101, 2):  # 90-100%: 完成打包
                self.progress.emit(i)
                self.msleep(50)
            
            logger.info('打包完成，准备保存...')
            self.finished.emit(True, "打包完成")
            
        except Exception as e:
            logger.error(f'打包失败: {str(e)}')
            self.finished.emit(False, str(e))

class MainWindow(QMainWindow):
    """主窗口类"""
    DIALOG_STYLE = """
        QMessageBox, QProgressDialog {
            background-color: white;
        }
        QPushButton {
            background-color: rgb(17, 24, 39);
            color: white;
            border: none;
            border-radius: 4px;
            padding: 6px 12px;
            min-width: 80px;
            min-height: 10px;
        }
        QPushButton:hover {
            background-color: rgb(31, 41, 55);
        }
        QLabel {
            min-width: 300px;
        }
        QProgressBar {
            border: none;
            background-color: rgb(229, 231, 235);
            border-radius: 2px;
            text-align: center;
        }
        QProgressBar::chunk {
            background-color: rgb(17, 24, 39);
            border-radius: 2px;
        }
    """
    
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.packager = Packager()
        self.package_worker = None
        self.start_time = None
        
    def init_ui(self):
        """初始化UI界面"""
        self.setWindowTitle('Python程序打包工具')
        self.setWindowIcon(get_app_icon())  # 设置窗口图标
        self.setMinimumSize(600, 300)
        self.setFixedSize(600, 300)  # 固定窗口大小
        self.setWindowFlags(Qt.Window | Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint)  # 只允许最小化和关闭
        
        # 主窗口整体样式定义
        self.setStyleSheet("""
            QMainWindow {
                background-color: white;
            }
            QGroupBox {
                border: 1px solid rgb(229, 231, 235);
                border-radius: 6px;
                padding: 12px;
                background-color: rgb(249, 250, 251);
            }
            QPushButton {
                background-color: white;
                border: 1px solid rgb(229, 231, 235);
                border-radius: 4px;
                padding: 8px 16px;
                color: rgb(31, 41, 55);
            }
            QPushButton:hover {
                background-color: rgb(249, 250, 251);
            }
            QPushButton#startButton {
                background-color: rgb(17, 24, 39);
                color: white;
                border: none;
            }
            QPushButton#startButton:hover {
                background-color: rgb(31, 41, 55);
            }
            QLabel {
                color: rgb(31, 41, 55);
            }
            QRadioButton {
                color: rgb(31, 41, 55);
                spacing: 8px;
            }
        """)
        
        # 创建中心部件和主布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout()
        main_layout.setSpacing(15)  # 减小整体间距
        main_layout.setContentsMargins(16, 12, 16, 12)  # 减小上下边距
        
        # 文件选择区域
        file_section = QVBoxLayout()
        file_section.setSpacing(15)  # 减小标签和内容的间距
        file_section_label = QLabel("文件选择")
        file_section_label.setStyleSheet("font-weight: bold;")
        file_section.addWidget(file_section_label)
        
        file_select_layout = QHBoxLayout()
        file_select_layout.setSpacing(15)
        self.select_file_btn = QPushButton('选择Python文件')
        self.select_file_btn.setFixedWidth(120)
        self.select_file_btn.setFixedHeight(36)
        file_select_layout.addWidget(self.select_file_btn)
        
        self.file_path_label = QLabel()
        self.file_path_label.setFixedHeight(36)
        self.file_path_label.setStyleSheet("""
            background-color: rgb(249, 250, 251);
            border: 1px solid rgb(229, 231, 235);
            border-radius: 4px;
            padding: 0 12px;
            line-height: 36px;
        """)
        file_select_layout.addWidget(self.file_path_label)
        file_section.addLayout(file_select_layout)
        main_layout.addLayout(file_section)
        
        # 打包配置标签
        config_label = QLabel("打包配置")
        config_label.setStyleSheet("font-weight: bold; margin-top: 8px;")  # 增加上边距
        main_layout.addWidget(config_label)
        
        # 配置组框
        config_group = QGroupBox()
        config_layout = QVBoxLayout()
        config_layout.setSpacing(15)
        config_layout.setContentsMargins(12, 8, 12, 8)
        
        # 图标选择按钮
        self.select_icon_btn = QPushButton('选择图标(可选)')
        self.select_icon_btn.setFixedHeight(36)
        self.select_icon_btn.setMinimumWidth(180)
        config_layout.addWidget(self.select_icon_btn)
        
        # 打包选项组（水平布局）
        package_options_layout = QHBoxLayout()
        package_options_layout.setSpacing(20)  # 增加组件之间的间距

        # 左侧打包选项
        left_layout = QHBoxLayout()
        pack_type_label = QLabel("打包:")
        pack_type_label.setStyleSheet("color: rgb(107, 114, 128); font-size: 12px;")
        left_layout.addWidget(pack_type_label)
        left_layout.addSpacing(8)  # 标题和选项之间的间距
        
        # 文件类型选择
        file_type_group = QButtonGroup(self)
        self.single_file_radio = QRadioButton("exe")
        self.single_file_radio.setChecked(True)
        self.directory_radio = QRadioButton("文件夹")
        file_type_group.addButton(self.single_file_radio)
        file_type_group.addButton(self.directory_radio)
        left_layout.addWidget(self.single_file_radio)
        left_layout.addWidget(self.directory_radio)
        
        package_options_layout.addLayout(left_layout)

        # 添加一个弹性空间
        package_options_layout.addStretch(1)

        # 右侧控制台选项
        right_layout = QHBoxLayout()
        console_label = QLabel("控制台:")
        console_label.setStyleSheet("color: rgb(107, 114, 128); font-size: 12px;")
        right_layout.addWidget(console_label)
        right_layout.addSpacing(8)  # 标题和选项之间的间距

        # 控制台显示选项
        console_group = QButtonGroup(self)
        self.show_console_radio = QRadioButton("显示")
        self.hide_console_radio = QRadioButton("隐藏")
        self.show_console_radio.setChecked(True)
        console_group.addButton(self.show_console_radio)
        console_group.addButton(self.hide_console_radio)
        right_layout.addWidget(self.show_console_radio)
        right_layout.addWidget(self.hide_console_radio)
        
        package_options_layout.addLayout(right_layout)

        config_layout.addLayout(package_options_layout)
        config_group.setLayout(config_layout)
        main_layout.addWidget(config_group)
        
        # 添加一个弹性空间
        main_layout.addStretch(1)
        
        # 打包按钮
        self.start_pack_btn = QPushButton('开始打包')
        self.start_pack_btn.setObjectName('startButton')
        self.start_pack_btn.setFixedHeight(36)
        main_layout.addWidget(self.start_pack_btn)
        
        # 底部间距
        main_layout.addSpacing(12)
        
        central_widget.setLayout(main_layout)
        
        # 连接信号
        self.select_file_btn.clicked.connect(self.select_file)
        self.select_icon_btn.clicked.connect(self.select_icon)
        self.start_pack_btn.clicked.connect(self.start_packaging)

    def select_file(self):
        """选择Python文件或目录"""
        file_path, _ = QFileDialog.getOpenFileName(self, '选择Python文件', '', 'Python Files (*.py)')
        if file_path:
            if validate_python_file(file_path):
                self.file_path_label.setText(file_path)
                logger.info(f'已选择文件: {file_path}')
            else:
                logger.error('所选文件不是有效的Python文件')
    
    def clear_icon(self):
        """清除已选择的图标"""
        self.packager.set_icon(None)
        self.select_icon_btn.setText('选择图标(可选)')
        logger.info('已清除图标设置')
    
    def show_message_box(self, title, message, icon_type='info', auto_close_ms=0):
        """
        显示消息框的统一方法
        
        Args:
            title: 标题
            message: 消息内容
            icon_type: 图标类型 ('info', 'warning', 'error')
            auto_close_ms: 自动关闭时间(毫秒),0表示不自动关闭
        """
        msg_box = QMessageBox(self)
        msg_box.setWindowTitle(title)
        msg_box.setText(message)
        
        # 设置图标
        icon_map = {
            'info': QMessageBox.Information,
            'warning': QMessageBox.Warning,
            'error': QMessageBox.Critical
        }
        msg_box.setIcon(icon_map.get(icon_type, QMessageBox.Information))
        
        msg_box.setStandardButtons(QMessageBox.Ok)
        msg_box.button(QMessageBox.Ok).setText('确定')
        msg_box.setFixedSize(400, 150)
        msg_box.setWindowFlags(msg_box.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        msg_box.setStyleSheet(self.DIALOG_STYLE)
        
        # 自动关闭
        if auto_close_ms > 0:
            QTimer.singleShot(auto_close_ms, msg_box.accept)
        
        msg_box.exec_()
    
    def convert_to_ico(self, image_path):
        """
        将图片转换为ico格式
        
        Args:
            image_path (str): 图片路径
            
        Returns:
            str: 生成的ico文件路径，转换失败返回None
        """
        try:
            # 确保临时目录存在
            temp_dir = settings.temp_dir
            if not temp_dir.exists():
                temp_dir.mkdir(parents=True)
                
            # 生成临时ico文件路径
            ico_filename = f"temp_icon_{os.path.splitext(os.path.basename(image_path))[0]}.ico"
            ico_path = temp_dir / ico_filename
            
            # 打开并转换图片
            with Image.open(image_path) as img:
                # 转换为RGBA模式
                if img.mode != 'RGBA':
                    img = img.convert('RGBA')
                    
                # 准备不同尺寸的图标
                icon_sizes = [(16,16), (32,32), (48,48), (64,64), (128,128), (256,256)]
                icons = []
                for size in icon_sizes:
                    resized_img = img.resize(size, Image.Resampling.LANCZOS)
                    icons.append(resized_img)
                
                # 保存为ico文件
                icons[0].save(
                    str(ico_path),
                    format='ICO',
                    sizes=[(i.width, i.height) for i in icons],
                    append_images=icons[1:]
                )
                
                logger.info(f'图片已转换为ico格式: {ico_path}')
                return str(ico_path)
                
        except Exception as e:
            logger.error(f'图片转换失败: {str(e)}')
            return None
    
    def select_icon(self):
        """选择图标文件"""
        icon_path, _ = QFileDialog.getOpenFileName(
            self, 
            '选择图标', 
            '', 
            'Image Files (*.ico *.png *.jpg *.jpeg *.bmp *.gif);;Icon Files (*.ico)'
        )
        if icon_path:
            try:
                final_icon_path = icon_path
                # 如果不是ico文件，进行转换
                if not icon_path.lower().endswith('.ico'):
                    converted_path = self.convert_to_ico(icon_path)
                    if converted_path:
                        final_icon_path = converted_path
                    else:
                        self.show_message_box('错误', '图片转换失败，请选择其他图片或ico文件', 'warning')
                        return
                    
                self.packager.set_icon(final_icon_path)
                
                # 更新按钮文字为文件名，保持原有样式
                if icon_path.lower().endswith('.ico'):
                    filename = os.path.basename(icon_path)
                else:
                    filename = os.path.basename(final_icon_path)
                
                # 根据按钮宽度计算可显示的文字长度
                max_length = 15  # 根据按钮宽度180px估算的最大字符数
                if len(filename) > max_length:
                    filename = filename[:max_length-3] + "..."
                self.select_icon_btn.setText(filename)
                logger.info(f'已设置图标: {final_icon_path}')
                
            except Exception as e:
                logger.error(f'处理图标文件失败: {str(e)}')
                self.show_message_box('错误', f'处理图标文件失败:\n{str(e)}', 'error')
    
    def package_finished(self, success, message):
        """打包完成处理"""
        try:
            if success:
                # 计算总耗时
                total_time = time.time() - self.start_time
                time_str = f"{total_time:.1f}秒"
                
                # 选择保存位置
                save_dir = QFileDialog.getExistingDirectory(
                    self, "选择保存位置",
                    str(settings.default_save_dir),
                    QFileDialog.ShowDirsOnly
                )
                
                if save_dir:
                    try:
                        self.packager.save_package(save_dir)
                        logger.info(f'文件已成功保存到: {save_dir}')
                        logger.info(f'打包总耗时: {time_str}')
                        
                        self.show_message_box('打包成功', f'打包完成！\n保存位置: {save_dir}\n总耗时: {time_str}', 'info', 1500)
                    except Exception as e:
                        self.show_message_box('保存失败', f'无法保存文件到指定位置:\n{str(e)}', 'warning')
            else:
                self.show_message_box('打包失败', f'打包过程出现错误:\n{message}', 'warning')
        finally:
            # 清理临时图标文件(保留临时目录)
            temp_dir = settings.temp_dir
            if temp_dir.exists():
                try:
                    # 只清理临时图标文件,不删除整个目录
                    for file in temp_dir.glob('temp_icon_*.ico'):
                        file.unlink()
                        logger.info(f'清理临时图标文件: {file.name}')
                except Exception as e:
                    logger.error(f'清理临时文件失败: {str(e)}')
            
            # 重新启用按钮
            self.start_pack_btn.setEnabled(True)
            self.select_file_btn.setEnabled(True)
            self.select_icon_btn.setEnabled(True)
    
    def start_packaging(self):
        """开始打包流程"""
        if not self.file_path_label.text():
            self.show_message_box('提示', '请先选择Python文件', 'warning')
            return
        
        # 检查是否有正在运行的打包任务
        if self.package_worker and self.package_worker.isRunning():
            self.show_message_box('提示', '打包任务正在进行中,请稍候', 'warning')
            return
            
        try:
            # 获取打包选项
            is_single_file = self.single_file_radio.isChecked()
            show_console = self.show_console_radio.isChecked()
            
            # 显示进度对话框
            progress_dialog = QProgressDialog("正在打包中，请稍候...", None, 0, 100, self)
            progress_dialog.setWindowTitle("打包进度")
            progress_dialog.setWindowModality(Qt.WindowModal)
            progress_dialog.setAutoClose(True)
            progress_dialog.setAutoReset(True)
            progress_dialog.setMinimumDuration(0)
            progress_dialog.setFixedSize(400, 80)
            progress_dialog.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint)
            progress_dialog.setStyleSheet("""
                QProgressDialog {
                    background-color: white;
                }
                QProgressBar {
                    border: none;
                    background-color: rgb(229, 231, 235);
                    border-radius: 2px;
                    text-align: center;
                    min-height: 10px;
                    max-height: 10px;
                }
                QProgressBar::chunk {
                    background-color: rgb(17, 24, 39);
                    border-radius: 2px;
                }
                QLabel {
                    min-width: 300px;
                    padding: 20px;
                }
            """)
            
            # 创建打包工作线程
            self.package_worker = PackageWorker(
                self.packager,
                self.file_path_label.text(),
                is_single_file,
                show_console
            )
            
            # 连接信号
            self.package_worker.progress.connect(progress_dialog.setValue)
            self.package_worker.finished.connect(lambda success, msg: (
                progress_dialog.close(),  # 立即关闭进度对话框
                QTimer.singleShot(100, lambda: self.package_finished(success, msg))  # 延迟显示保存对话框
            ))
            
            # 禁用按钮
            self.start_pack_btn.setEnabled(False)
            self.select_file_btn.setEnabled(False)
            self.select_icon_btn.setEnabled(False)
            
            # 记录开始时间
            self.start_time = time.time()
            
            # 开始打包
            self.package_worker.start()
            
        except Exception as e:
            QMessageBox.critical(self, '错误', f'启动打包失败: {str(e)}')